﻿#include "PortItem.h"
#include <QPainter>

namespace Graphics
{
    class PortItemPrivater
    {
    public:
        PortItemPrivater(PortItem * item)
        {
            /// get graphics item width as base width
            QGraphicsObject * obj = item->parentObject();
            if (obj)
            {
                _baseWidth = obj->boundingRect().width();
            }
        }

        /**
         * @brief     Size Of The Port.
         * @author    maguiwa(maguiwa520@163.com)
         * @date      2024-8-31 11:25
         */
        int _size{ 10 };

        /**
         * @brief     Pen to Draw Port Item Frame
         * @author    maguiwa(maguiwa520@163.com)
         * @date      2024-8-31 11:27
         */
        QPen _pen{ QPen(QColor(128,128,128),1) };

        /**
         * @brief     Brush to Draw Port Item
         * @author    maguiwa(maguiwa520@163.com)
         * @date      2024-8-31 11:28
         */
        QBrush _brush{ QBrush(QColor(56,56,56)) };

        /**
         * @brief     input port state
         * @author    maguiwa(maguiwa520@163.com)
         * @date      2024-8-31 11:33
         */
        QPair<PortType, PortState> _inputState{ Port_Type_Input,Port_State_Normal };

        /**
         * @brief     output port state
         * @author    maguiwa(maguiwa520@163.com)
         * @date      2024-8-31 11:34
         */
        QPair<PortType, PortState> _outputState{ Port_Type_Output,Port_State_Normal };

        /**
         * @brief     Graphics object width
         * @author    maguiwa(maguiwa520@163.com)
         * @date      2024-8-31 11:39
         */
        int _baseWidth{};
    };

    PortItem::PortItem(QGraphicsObject * parent)
        : QGraphicsObject(parent)
        , _private(new PortItemPrivater(this))
    {

    }

    PortItem::~PortItem()
    {
        if (_private)
        {
            delete _private;
            _private = nullptr;
        }
    }

    int PortItem::size() const
    {
        return _private->_size;
    }

    void PortItem::setSize(int size)
    {
        _private->_size = size;
        update();
    }

    QPen PortItem::framePen() const
    {
        return _private->_pen;
    }

    void PortItem::setFramePen(QPen pen)
    {
        _private->_pen = pen;
        update();
    }

    QBrush PortItem::selectedBrush() const
    {
        return _private->_brush;
    }

    void PortItem::setSelectedBrush(QBrush brush)
    {
        _private->_brush = brush;
    }

    void PortItem::setPortState(PortType type, PortState state)
    {
        if (Port_Type_Input == type)
        {
            if (state != _private->_inputState.second)
            {
                _private->_inputState.second = state;
                update();
            }
        }
        else if (Port_Type_Output == type)
        {
            if (state != _private->_outputState.second)
            {
                _private->_outputState.second = state;
                update();
            }
        }
    }

    PortState PortItem::portState(PortType type) const
    {
        if (Port_Type_Input == type)
            return _private->_inputState.second;
        else
            return _private->_outputState.second;
    }

    QRectF PortItem::boundingRect() const
    {
        return QRectF(0, 0, _private->_baseWidth + _private->_size, _private->_size);
    }

    void PortItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget /* = nullptr */)
    {
        Q_UNUSED(option)
            Q_UNUSED(widget)

            painter->save();

        /// construct input output rect
        QRectF inputPortRect(0, 0, _private->_size, _private->_size);
        QRectF outputPortRect(_private->_baseWidth, 0, _private->_size, _private->_size);

        /// draw input and output port
        drawPort(painter, _private->_inputState.second, inputPortRect);
        drawPort(painter, _private->_outputState.second, outputPortRect);

        painter->restore();
    }

    QPoint PortItem::outputPortPos()
    {
        QPoint pt = this->scenePos().toPoint();
        return QPoint(pt.x() + _private->_baseWidth + _private->_size / 2, pt.y() + _private->_size / 2);
    }

    QPoint PortItem::inputPortPos()
    {
        QPoint pt = this->scenePos().toPoint();
        return QPoint(pt.x() + _private->_size / 2, pt.y() + _private->_size / 2);
    }

    void PortItem::drawPort(QPainter *painter, PortState state, QRectF rect)
    {
        if (Port_State_Normal == state ||
            Port_State_Selected == state)
        {
            painter->setPen(Qt::NoPen);
            painter->setBrush(Qt::NoBrush);
        }
        else if (Port_State_Nearby == state)
        {
            painter->setPen(_private->_pen);
            painter->setBrush(Qt::NoBrush);
        }
        else if (Port_State_Selected_Nearby == state)
        {
            painter->setPen(_private->_pen);
            painter->setBrush(_private->_brush);
        }
        painter->drawRect(rect);
    }

}